{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit FormPosition;

interface

uses Classes, Forms;

type
  TAHMFormPosition = class
  private
    FLeft: Integer;
    FTop: Integer;
    FWidth: Integer;
    FHeight: Integer;
    FMaximized: Boolean;
  public
    property Left: Integer read FLeft write FLeft;
    property Top: Integer read FTop write FTop;
    property Width: Integer read FWidth write FWidth;
    property Height: Integer read FHeight write FHeight;
    property Maximized: Boolean read FMaximized write FMaximized;
    procedure Assign(Source: TAHMFormPosition);
  end;

  TAHMFormProperty = class
  private
    FControl: String;
    FProperty: String;
    FPrevVal: Integer;
    FCurrVal: Integer;
  public
    property ControlName: String read FControl write FControl;
    property PropertyName: String read FProperty write FProperty;
    property PreviousValue: Integer read FPrevVal write FPrevVal;
    property CurrentValue: Integer read FCurrVal write FCurrVal;
    procedure Assign(Source: TAHMFormProperty);
  end;

  TAHMFormState = class
  private
    FSaved: Boolean;
    FPrevPos: TAHMFormPosition;
    FCurrPos: TAHMFormPosition;
    FProperties: TList;
  protected
    function GetPropertyCount: Integer;
    function GetProperty(Index: Integer): TAHMFormProperty; overload;
  public
    constructor Create;
    destructor Destroy; override;
    property PreviousPosition: TAHMFormPosition read FPrevPos;
    property CurrentPosition: TAHMFormPosition read FCurrPos;
    property PropertyCount: Integer read GetPropertyCount;
    property Properties[Index: Integer]: TAHMFormProperty read GetProperty; default;
    property Saved: Boolean read FSaved;
    function AddProperty: TAHMFormProperty; overload;
    function AddProperty(const ControlName, PropertyName: String): TAHMFormProperty; overload;
    function GetProperty(const ControlName, PropertyName: String): TAHMFormProperty; overload;
    procedure ClearProperties;
    procedure SaveFormState(Form: TForm);
    procedure RestoreFormState(Form: TForm);
  end;

implementation

uses Windows, TypInfo;

// TAHMFormPosition

procedure TAHMFormPosition.Assign(Source: TAHMFormPosition);
begin
  FLeft := Source.Left;
  FTop := Source.Top;
  FWidth := Source.Width;
  FHeight := Source.Height;
  FMaximized := Source.Maximized;
end;

// TAHMFormProperty

procedure TAHMFormProperty.Assign(Source: TAHMFormProperty);
begin
  FControl := Source.ControlName;
  FProperty := Source.PropertyName;
  FPrevVal := Source.PreviousValue;
  FCurrVal := Source.CurrentValue;
end;

// TAHMFormState

constructor TAHMFormState.Create;
begin
  inherited;

  FPrevPos := TAHMFormPosition.Create;
  FCurrPos := TAHMFormPosition.Create;
  FProperties := TList.Create;
end;

destructor TAHMFormState.Destroy;
begin
  ClearProperties;
  FProperties.Free;
  FPrevPos.Free;
  FCurrPos.Free;

  inherited;
end;

function TAHMFormState.GetPropertyCount: Integer;
begin
  Result := FProperties.Count;
end;

function TAHMFormState.GetProperty(Index: Integer): TAHMFormProperty;
begin
  Result := TAHMFormProperty(FProperties[Index]);
end;

function TAHMFormState.AddProperty: TAHMFormProperty;
begin
  Result := TAHMFormProperty.Create;
  FProperties.Add(Result);
end;

function TAHMFormState.AddProperty(const ControlName, PropertyName: String): TAHMFormProperty;
begin
  Result := AddProperty;
  Result.ControlName := ControlName;
  Result.PropertyName := PropertyName;
end;

function TAHMFormState.GetProperty(const ControlName, PropertyName: String): TAHMFormProperty;
var
  i: Integer;
begin
  for i := 0 to Pred(FProperties.Count) do
  begin
    Result := TAHMFormProperty(FProperties[i]);
    if (Result.ControlName = ControlName) and
       (Result.PropertyName = PropertyName) then Exit;
  end;

  // Not found
  Result := nil;
end;

procedure TAHMFormState.ClearProperties;
var
  i: Integer;
begin
  for i := 0 to Pred(FProperties.Count) do
    TAHMFormProperty(FProperties[i]).Free;

  FProperties.Clear;
end;

procedure TAHMFormState.SaveFormState(Form: TForm);
var
  Place: TWindowPlacement;
  Prop: TAHMFormProperty;
  Comp: TComponent;
  Rect: TRect;
  i: Integer;
begin
  // Save form to current position properties
  if Assigned(Form) then
  begin
    // Get non-maximized size of form to persist
    Place.Length := SizeOf(TWindowPlacement);
    GetWindowPlacement(Form.Handle, @Place);
    Rect := Place.rcNormalPosition;

    FCurrPos.Top := Rect.Top;
    FCurrPos.Left := Rect.Left;
    FCurrPos.Width := Rect.Right - Rect.Left;
    FCurrPos.Height := Rect.Bottom - Rect.Top;
    FCurrPos.Maximized := Form.WindowState = wsMaximized;

    // Get values of form properties
    for i := 0 to Pred(FProperties.Count) do
    begin
      Prop := TAHMFormProperty(FProperties[i]);
      if Prop.ControlName <> '' then
        Comp := Form.FindComponent(Prop.ControlName)
      else
        Comp := Form;
      Prop.CurrentValue := GetOrdProp(Comp, Prop.PropertyName);
    end;

    // Form properties now saved
    FSaved := True;
  end;
end;

procedure TAHMFormState.RestoreFormState(Form: TForm);
var
  Prop: TAHMFormProperty;
  Comp: TComponent;
  i: Integer;
begin
  // Apply previous position properties to form
  if Assigned(Form) then
  begin
    Form.Top := FPrevPos.Top;
    Form.Left := FPrevPos.Left;
    if FPrevPos.Width > 0 then Form.Width := FPrevPos.Width;
    if FPrevPos.Height > 0 then Form.Height := FPrevPos.Height;
    if FPrevPos.Maximized then Form.WindowState := wsMaximized
                          else Form.WindowState := wsNormal;

    // Set values of form properties
    for i := 0 to Pred(FProperties.Count) do
    begin
      Prop := TAHMFormProperty(FProperties[i]);
      if Prop.ControlName <> '' then
        Comp := Form.FindComponent(Prop.ControlName)
      else
        Comp := Form;
      SetOrdProp(Comp, Prop.PropertyName, Prop.PreviousValue);
    end;
  end;
end;

end.
